/*
 * Copyright(C) 2009, kesalin All rights reserved.
 * 
 * File name : TaskTrayWindow.h
 * Brief     : Dummy Window for task tray.
 * Version   : 1.0
 * Author    : kesalin@gmail.com
 * Date      : 2009-6-8
 */

#pragma once
#include "resource.h"
#include <atlbase.h>
#include <Shellapi.h>
#include <shobjidl.h>

using namespace LuoTaskTray;

// TaskTrayWindow
class TaskTrayWindow :
	public LuoTaskTray::XTopLevelWindow,
	public ATL::CDialogImpl<TaskTrayWindow> {

	HICON hIcon;

	ATL::CComPtr<IShellFolder> m_Folder;
	ATL::CComPtr<IContextMenu3> m_ContextMenu;
public:
	HWND m_hTarget;
	UINT m_nCallback;
public:
	enum {
		IDD			= IDD_BASE
	};

	TaskTrayWindow() :
	m_hTarget(0),
	m_nCallback(0),
	hIcon(0),
	m_Folder(0),
	m_ContextMenu(0)
	{
	}

	~TaskTrayWindow()
	{
	}

	static TaskTrayWindow* CreateFrame(LuoTaskTray::UCreateParam * param)
	{
		TaskTrayWindow*	 frame = new TaskTrayWindow();
		if (param) {
			frame->m_hTarget = param->hwnd;
			frame->m_nCallback = param->CallbackMessage;
		}

		HWND hwnd = frame->Create(NULL, (LPARAM) 0);
		if (hwnd == 0) {
			delete frame;
			return 0;
		}

		return frame;
	}

	/* */
	virtual void OnFinalMessage(HWND hWnd)
	{
		delete this;
	}

	virtual void STDCALL FinalRelease()
	{
		HWND hwnd = *this;
		if (hwnd != 0) {
			::DestroyWindow(hwnd);
		}
	}

	virtual bool STDCALL PreprocessWindowMessage(MSG* msg)
	{
		return false;
	}

	/* */
	BEGIN_MSG_MAP_EX(TaskTrayWindow)
	MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
	MSG_WM_ERASEBKGND(OnEraseBkGnd)
	//MSG_WM_PAINT(OnPaint)
	MSG_WM_DESTROY(OnDestroy)
	MESSAGE_HANDLER(WM_INITMENUPOPUP, OnMenuHandler)
	MESSAGE_HANDLER(WM_DRAWITEM, OnMenuHandler)
	MESSAGE_HANDLER(WM_MENUCHAR, OnMenuHandler)
	MESSAGE_HANDLER(WM_MEASUREITEM, OnMenuHandler)
	MESSAGE_HANDLER(WM_COMMAND, OnCommand)
	MESSAGE_HANDLER(LuoTaskTray::WM_TASK_TRAY_MENU_CALLBACK, OnTaskTrayCallback)
	MESSAGE_HANDLER(LuoTaskTray::WM_INVOKE_SHELL_ITEM_MENU, OnInvokeShellItemMenu)
	REFLECT_NOTIFICATIONS()
	END_MSG_MAP()
	/* */
	LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		SetWindowText(_T("LuoTaskTray"));
		ModifyStyleEx(0, WS_EX_TOOLWINDOW);

		SetWindowPos(0, 0, 0, 1, 1, SWP_NOZORDER);
		ShowWindow(SW_HIDE);

		// Load icon
		hIcon = ::LoadIcon(NULL, IDI_APPLICATION);

		// TODO: Load your icon here!
		//hIcon = ::LoadIcon((HINSTANCE) GetWindowLongPtr(GWLP_HINSTANCE), MAKEINTRESOURCE(IDI_ICON1));
		
		SetupTaskTrayIcon();

		HRESULT hRslt = SHGetDesktopFolder(&m_Folder);
		if (FAILED(hRslt)) {
			OutputDebugStringW(L"\n SHGetDesktopFolder failed\n\n");
		}

		SendMessage(LuoTaskTray::TTM_CREATED, (HWND) (*this));

		//////////////////////////////////////////////////////////////////////////
		return FALSE;
	}

	/* */
	BOOL OnEraseBkGnd(HDC
	/*hDC*/ )
	{
		return TRUE;
	}

	/* */
	void OnPaint(HDC hDC)
	{

	}

	/* */
	void OnDestroy()
	{
		DeleteTaskTrayIcon();

		if (hIcon) {
			DestroyIcon(hIcon);
			hIcon = 0;
		}

		m_Folder.Release();
		m_Folder = 0;

		WTL::CRect rc;
		GetWindowRect(&rc);

		SetMsgHandled(false);

		if (g_pUtils) {
			LuoTaskTray::g_pUtils->RemoveTopLevelWindow(this);
		}

		SendMessage(LuoTaskTray::TTM_CLOSED, NULL);
	}

	LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		int id = LOWORD(wParam);

		switch (id) {
		case IDOK:
		case IDCANCEL:
		case IDCLOSE:
			break;
		}

		return 0;
	}

	/* */
	void SendMessage(int cmd, HWND hwnd = NULL)
	{
		if (m_hTarget && m_nCallback) {
			::PostMessage(m_hTarget, m_nCallback, (WPARAM) cmd, (LPARAM) hwnd);
		}
	}

	/* */
	LRESULT OnTaskTrayCallback(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		int lp = (int)lParam;

		switch (lp) {
		case WM_RBUTTONUP: {
				InvokeTaskTrayMenu();
			}
			break;
		default:
			break;
		}

		return 0;
	}

	void SetupTaskTrayIcon()
	{
		NOTIFYICONDATA nid = { 0};
		nid.cbSize = NOTIFYICONDATA_V2_SIZE;
		nid.uID = 0;
		nid.hWnd = *this;
		nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
		nid.hIcon = hIcon;
		nid.uCallbackMessage = LuoTaskTray::WM_TASK_TRAY_MENU_CALLBACK;

		_tcscpy_s(nid.szTip, _T("LuoTaskTray"));
		Shell_NotifyIcon(NIM_ADD, &nid);
	}

	void DeleteTaskTrayIcon()
	{
		NOTIFYICONDATA nid = { 0};

		nid.cbSize = NOTIFYICONDATA_V2_SIZE;
		nid.uID = 0;
		nid.hWnd = *this;

		Shell_NotifyIcon(NIM_DELETE, &nid);
	}

	void InvokeTaskTrayMenu()
	{
		HWND hwnd = *this;

		WTL::CPoint pt;
		GetCursorPos(&pt);

		// create menu
		WTL::CMenu popup;
		popup.CreatePopupMenu();

		// TODO: Insert your menu items here!
		int i = 0;
		popup.InsertMenu(i++, MF_BYPOSITION, LuoTaskTray::TTM_EXIT, _T("Exit"));

		// track popup menu
		SetForegroundWindow(hwnd);

		HMENU hMenu = popup.Detach();
		int code = TrackPopupMenu(
				hMenu,
				TPM_RIGHTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD,
				pt.x,
				pt.y,
				0,
				hwnd,
				0);

		popup.DestroyMenu();

		::PostMessageW(hwnd, WM_NULL, 0, 0);

		// post message
		SendMessage(code);
	}

	/* */
	LRESULT OnInvokeShellItemMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if (m_Folder != 0) {
			InvokeShellItemMenu(*this, (ITEMIDLIST*)lParam);
		}

		return 0;
	}

	void InvokeShellItemMenu(HWND hwnd, ITEMIDLIST* itemId)
	{
		ATL::CComPtr<IContextMenu> cm;
		HRESULT hRslt = m_Folder->GetUIObjectOf(
				hwnd,
				1,
				(LPCITEMIDLIST*) &(itemId),
				IID_IContextMenu,
				0,
				(void**) &cm);
		if (FAILED(hRslt)) {
			return;
		}

		HMENU hMenu = ::CreatePopupMenu();

		hRslt = cm->QueryContextMenu(hMenu, 0, 1, 0x7fff, CMF_NORMAL);
		if (SUCCEEDED(hRslt)) {
			WTL::CPoint pt;
			::GetCursorPos(&pt);

			m_ContextMenu.Release();
			cm->QueryInterface(&m_ContextMenu);

			SetForegroundWindow(hwnd);

			int cmd = ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON, pt.x, pt.y, 0, hwnd, 0);

			::PostMessageW(hwnd, WM_NULL, 0, 0);

			m_ContextMenu.Release();

			if (cmd != 0) {
				CMINVOKECOMMANDINFO ci = { 0};
				ci.cbSize = sizeof(ci);
				ci.hwnd = hwnd;
				ci.lpVerb = (LPCSTR) MAKEINTRESOURCE(cmd - 1);
				ci.nShow = SW_SHOWNORMAL;

				cm->InvokeCommand(&ci);
			}
		}

		::DestroyMenu(hMenu);
	}

	LRESULT OnMenuHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LRESULT lResult = 0;

		if (m_ContextMenu != 0) {
			m_ContextMenu->HandleMenuMsg2(uMsg, wParam, lParam, &lResult);
		}

		return lResult;
	}
};

// TaskTrayWindow
